package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.deer.wms.base.system.dao.ErpBackRecordMapper;
import com.deer.wms.base.system.service.CellInfoService;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.BeanUtils;
import com.deer.wms.system.manage.model.user.UserInfo;
import com.deer.wms.ware.task.model.pushErp.StrategyErpService;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.WaveDetailMapper;
import com.deer.wms.ware.task.model.SO.SoDetail;
import com.deer.wms.ware.task.model.SO.SoMaster;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.Wave.WaveDetailCriteria;
import com.deer.wms.ware.task.model.Wave.WaveDetailDto;
import com.deer.wms.ware.task.model.Wave.WaveMaster;
import com.deer.wms.ware.task.model.out.OutDetail;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author wei
 * @date 2020/02/02
 */
@Service
@Transactional
public class WaveDetailServiceImpl extends SuperServiceImpl<WaveDetailMapper, WaveDetail> implements WaveDetailService {

    @Autowired
    private WaveDetailMapper waveDetailMapper;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private SoMasterServiceImpl soMasterService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private SoDetailService soDetailService;
    @Autowired
    private InventoryTransactService inventoryTransactService;
    @Autowired
    private ErpBackRecordMapper erpBackRecordMapper;
    @Autowired
    private OutMasterService outMasterService;

    @Autowired
    private PushErpService pushErpService;
    @Autowired
    private CellInfoService cellInfoService;

    @Autowired
    private AsyncService asyncService;
    @Autowired
    private StrategyErpService strategyErpService;


    @Override
    public List<WaveDetailDto> findList(WaveDetailCriteria criteria) {

//        Set<String> collect = list.stream().map(WaveDetailDto::getItemCode).collect(Collectors.toSet());
        return waveDetailMapper.findList(criteria);


    }

    @Override
    public List<WaveDetail> getByMasterId(Integer waveId) {
        return waveDetailMapper.getByMasterId(waveId);
    }

    @Override
    public void deleteByWaveMasterId(Integer id) {

        WaveDetailCriteria criteria = new WaveDetailCriteria();
        criteria.setWaveId(id);
        waveDetailMapper.deleteByWaveMasterCode(criteria);
    }

    @Override
    public void suggestForPick(List<WaveDetail> detailList, UserInfo wareUser, CurrentUser currentUser) {
        //波次明细 关联 仓库员
        for (WaveDetail waveDetail : detailList) {
            //波次明细绑定仓管员。  后续拣货是按仓管员分组进行操作
            //不能更换仓管员
            if (ObjectUtil.equals(WareTaskConstant.WAVE_STATE_PICKING, waveDetail.getState()) && ObjectUtil.notEqual(wareUser.getUserId(),
                    waveDetail.getPickUserId())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "部分推荐的波次明细不允许更换仓管员");
            }

            waveDetail.setPickUserId(wareUser.getUserId());
            waveDetail.setPickUserName(wareUser.getUserName());
        }
        WaveMaster waveMaster = waveMasterService.getById(detailList.get(0).getWaveMasterId());
        if (waveMaster.getState().equals(WareTaskConstant.OUT_STATE_INIT)) {
            waveMaster.setState(WareTaskConstant.OUT_STATE_DOING);
            waveMasterService.updateById(waveMaster);
        }

        //分配库存
        Set<Integer> wareDetailIds = detailList.stream().map(WaveDetail::getWaveDetailId).collect(Collectors.toSet());
        List<SoDetail> soDetails = soDetailService.list(new QueryWrapper<SoDetail>().in("wave_detail_id", wareDetailIds));
        for (SoDetail soDetail : soDetails) {
            pickTaskService.createPickTask(soDetail, currentUser);
        }
    }

    @Override
    public Map<String, String> sendOut(List<Integer> pickIds, CurrentUser currentUser,Integer wareId,String batchCode) {
        Map<String, String> returnMap = new HashMap<>();

        List<PickTask> pickTasks = pickTaskService.listByIds(pickIds);
        //找到对应的库存
        List<Integer> invIdList = pickTasks.stream().map(PickTask::getInventoryId).collect(Collectors.toList());
        List<Inventory> inventories = inventoryService.listByIds(invIdList);
        Set<OutDetail> outDetailSet = new HashSet<>();
        Set<SoDetail> soDetailSet = new HashSet<>();
        //先按波次明细分组  ArrayDeque
        Map<String, List<Inventory>> map = inventories.stream().filter(item -> ObjectUtil.isNotEmpty(item.getBillNo())).collect(Collectors.groupingBy(Inventory::getBillNo));
        Set<String> waveDetailCodes = map.keySet();
        for (String waveDetailCode : waveDetailCodes) {
            WaveDetail waveDetail = waveDetailService.getOneByField("wave_detail_code", waveDetailCode);
            QueryWrapper<SoDetail> soDetailQw = new QueryWrapper<>();
            soDetailQw.eq("wave_detail_id", waveDetail.getWaveDetailId());
            //soDetailQw.ne("state", WareTaskConstant.SO_DETAIL_STATE_ALL_PICK); 目前做不到狀態管理
            List<SoDetail> soDetails = soDetailService.list(soDetailQw);
            ArrayDeque<SoDetail> ad = new ArrayDeque<>(soDetails);
            List<Inventory> allotInvs = map.get(waveDetailCode);
            //分配库存
            //多个库存对应一个波次明细   一个波次明细对应多个出库任务明细
            //  A1, A2, A3   ===>   B1
            //  B1  ===>  C1,C2,C3,C4,C5
            Set<OutDetail> extracted = extracted(ad, allotInvs, soDetailSet);
            outDetailSet.addAll(extracted);
        }
        System.out.println(Thread.currentThread().getName());

        //获取异步数据
        CompletableFuture<Map<String, String>> asyncMap = CompletableFuture.supplyAsync(
                () -> {
                    return asyncService.asyncPushErp(inventories, outDetailSet, currentUser);
                });

        //Step3.回写单据状态
        for (PickTask pickTask : pickTasks) {
            pickTask.setSeededQuantity(pickTask.getPickQuantity());
            pickTask.setState(WareTaskConstant.PICK_STATE_OUTED);
        }
//        if (true) {throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "test");}
        pickTaskService.updateBatchById(pickTasks);
//        try {
//            returnMap = asyncMap.get();
//            returnMap.put("msg", "提交成功");
//            return returnMap;
//
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        } catch (ExecutionException e) {
//            returnMap.put("code", "400");
//            returnMap.put("msg", e.getMessage());
//            e.printStackTrace();
//            return returnMap;
//
//        }
        return returnMap;

//
//        //Step4.生成出库单
//        OutDetail soDetail = outDetailSet.iterator().next();
//        SoMaster soMaster = soMasterService.getOneByField("bill_no", soDetail.getBillNo());
//        String outBill = outMasterService.createOutBill(soMaster, outDetailSet, currentUser);
//
//        //Step2.处理库存，生成库存事务
//        for (Inventory inventory : inventories) {
//            this.toStockRequest(inventory, currentUser);
//            inventoryService.removeById(inventory);
//        }
//
//        //Step5.修改soMaster出库数量方便齐套检查
//     this.updateMaster(outDetailSet);
//        //Step6.回传Erp
//        OrderToErpBO erpBean = this.getErpBean(outDetailSet,outBill);
//        pushErpService.pushIMBIll(erpBean);


    }

    @Autowired
    private WaveMasterService waveMasterService;

    /**
     * 同步最新的数据（如皋需求，因为可能期间发生变化）
     *
     * @param waveCode 波次号
     */
    @Override
    public void syncCurrentData(String waveCode) {
        //1.整理数据，将明细行获取为一个set
        //2.将新旧soDetails 变为Map ，key为明细行
//        List<SoDetail> allSoDetails = new ArrayList<>();
////        List<SoDetail> newSoDetails = soDetailService.syncCurrentData();
//        List<SoDetail> oldSoDetails = this.getSoDetailsByWaveCode(waveCode);
//        allSoDetails.addAll(oldSoDetails);
//        allSoDetails.addAll(newSoDetails);
//
//        new HashSet<>(allSoDetails);
//
//
//        //行号可能重复，不能作为唯一条件去重
//        Map<SoDetail, SoDetail> newMap = newSoDetails.stream()
//                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
//        Map<SoDetail, SoDetail> oldMap = oldSoDetails.stream()
//                .collect(Collectors.toMap(item -> item, soDetail -> soDetail, (oldValue, newValue) -> newValue));
//
//
//        //3.根据明细行去获取
//        for (SoDetail key : allSoDetails) {
//            SoDetail newSd = newMap.get(key);
//            SoDetail oldSd = oldMap.get(key);
//            if (newSd == null) {
//                //新增的为空，说明ERP删除了明细行
//                //WMS要做扣减soDetail  波次也要扣减
//                soDetailService.removeById(oldSd.getSoDetailId());
//                WaveDetail waveDetail = waveDetailService.getById(oldSd.getWaveDetailId());
//                if (waveDetail.getQuantity() > oldSd.getOrderQuantity()) {
//                    waveDetail.setQuantity(waveDetail.getQuantity() - oldSd.getOrderQuantity());
//                    waveDetailService.updateById(waveDetail);
//                } else {
//                    waveDetailService.removeById(waveDetail);
//                }
//            } else if (oldSd == null) {
//                //老的为空，说明ERP新增了明细行
//                //WMS要做新增
//                soDetailService.save(newSd);
//                SoMaster soMaster = soMasterService.getOneByField("bill_no", newSd.getBillNo());
//                WaveDetail waveDetail = waveDetailService.getOne(new QueryWrapper<WaveDetail>()
//                        .eq("wave_code", waveCode)
//                        .eq("item_code", newSd.getItemCode())
//                        .eq("rob", newSd.getRob()));
//                if (ObjectUtil.isNull(waveDetail)) {
//                    WaveMaster waveMaster = waveMasterService.getOneByField("code", waveCode);
//                    waveDetail = new WaveDetail(newSd);
//                    waveDetail.setRob(newSd.getRob());
//                    waveDetail.setQuantity(newSd.getOrderQuantity());
//                    waveDetail.setSoMasterId(soMaster.getSoMasterId());
//                    //波次单信息
//                    waveDetail.setWaveMasterId(waveMaster.getWaveId());
//                    waveDetail.setWaveCode(waveMaster.getCode());
//                    waveDetail.setWareId(waveMaster.getWareId());
//                    waveDetail.setWareName(waveMaster.getWareName());
//                } else {
//                    waveDetail.setQuantity(waveDetail.getQuantity() + newSd.getOrderQuantity());
//                    newSd.setWaveDetailId(waveDetail.getWaveDetailId());
//                }
//                soDetailService.updateById(newSd);
//                waveDetailService.saveOrUpdate(waveDetail);
//            } else {
//                //都有，则判断数量，有变化则修改
//                if (ObjectUtil.notEqual(oldSd.getOrderQuantity(), newSd.getOrderQuantity())) {
//                    Double newQty = newSd.getOrderQuantity();
//                    Double oldQty = oldSd.getOrderQuantity();
//                    oldSd.setOrderQuantity(newQty);
//                    soDetailService.updateById(oldSd);
//                    WaveDetail waveDetail = waveDetailService.getById(oldSd.getWaveDetailId());
//                    waveDetail.setQuantity(waveDetail.getQuantity() + (newSd.getOrderQuantity() - oldQty));
//                    waveDetailService.updateById(waveDetail);
//
//                }
//            }
//        }
    }

    @Override
    public List<WaveDetailDto> updateXfQuantity(List<WaveDetailDto> waveDetails) {
        List<WaveDetail> waveDetails1=new ArrayList<>();
        // 找到相应的出库任务明细 进行验收数量的扣减
        for (WaveDetailDto waveDetail : waveDetails) {
            // 1.先查出与波次明细相关的出库明细
            List<SoDetail> soDetails = soDetailService.getListByField("wave_detail_id", waveDetail.getWaveDetailId());
            // 该明细的先发配件数量
            Double xfQuantity=0.0;
            // 2.找到对应的出库任务(有先发配件库)
            for (SoDetail soDetail : soDetails) {
                SoMaster soMaster = soMasterService.getOneByField("bill_no", soDetail.getBillNo());
                QueryWrapper<Inventory> qw = Wrappers.query();
                Map<String, Object> map = new HashMap<>(4);

                //根据物料批次找到所有对应的库存
                map.put("ware_id", waveDetail.getWareId());
                // 增加筛选条件 库区 484153(先发配件库)
                map.put("erp_area_id", 484153);
                map.put("item_code", waveDetail.getItemCode());
                map.put("batch_name", soMaster.getTradeNo());
                List<Inventory> inventories = inventoryService.getBaseMapper().selectList(qw.allEq(map, true));
                // 如果查出的库存为 0 证明不是先发配件物料
                if (inventories.size() > 0) {
                    // 先发配件物料
                    for(Inventory inventory:inventories){
                        xfQuantity+=inventory.getQuantity();
                    }
                }
            }
            // 更新先发配件数量
            waveDetail.setXfQuantity(xfQuantity);
            WaveDetail detail = getOneByField("wave_detail_id", waveDetail.getWaveDetailId());
            detail.setXfQuantity(xfQuantity);
            waveDetails1.add(detail);
        }
        // 数据库更新--以后进行异步操作
        updateBatchById(waveDetails1);
        return waveDetails;
    }

    private List<SoDetail> getSoDetailsByWaveCode(String waveCode) {
        List<WaveDetail> waveDetails = waveDetailService.getListByField("wave_code", waveCode);
        Set<Integer> waveDetailIdsSet = waveDetails.stream()
                .filter(waveDetail -> waveDetail.getState() == WareTaskConstant.WAVE_STATE_PROCESSING)
                .map(waveDetail -> waveDetail.getWaveDetailId()).collect(Collectors.toSet());

        return soDetailService.list(new QueryWrapper<SoDetail>().in("wave_detail_id", waveDetailIdsSet));
    }


    public void updateMaster(Set<OutDetail> outDetails) {
        //过滤单号
        Set<String> billSet = outDetails.stream().map(OutDetail::getBillNo).collect(Collectors.toSet());
        //通过单号查soMaster
        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", billSet));
        //通过单号查SoDetail
        List<SoDetail> soDetailList = soDetailService.list(new QueryWrapper<SoDetail>().in("bill_no", billSet));
        //根据单号分组
        Map<String, List<SoDetail>> soDetailMap = soDetailList.stream().collect(Collectors.groupingBy(SoDetail::getBillNo));

        soMasterList.forEach(item -> {
            double deliverQty = soDetailMap.get(item.getBillNo()).stream().mapToDouble(SoDetail::getDeliveryQuantity).sum();
            item.setQcQty(item.getQcQty() + deliverQty);
        });
        soMasterService.updateBatchById(soMasterList);


//        Set<SoMaster> soMasterSet = new HashSet<>();
//        //根据订单号分组
//        Map<String, List<SoDetail>> detailMap = soDetails.stream().collect(Collectors.groupingBy(SoDetail::getBillNo));
//        //获取所有的订单号Key
//        Set<String> set = detailMap.keySet();
//        //获取出库单集合
//        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", set));
//        Map<String, List<SoMaster>> soMasterMap = soMasterList.stream().collect(Collectors.groupingBy(SoMaster::getBillNo));
//        detailMap.forEach((key,val)->{
//            double deliverQty = detailMap.get(key).stream().mapToDouble(SoDetail::getDeliveryQuantity).sum();
//            //新增出库数量
//            SoMaster soMaster = soMasterMap.get(key).get(0);
//            soMaster.setQcQty(soMaster.getQcQty() + deliverQty);
//            soMasterSet.add(soMaster);
//        });
//        //批量修改
//        soMasterService.updateBatchById(soMasterSet);
    }

    /**
     * 分配数量，更新
     *
     * @param queue       SO 队列
     * @param allotInvs   待分配的库存
     * @param soDetailSet
     */
    private Set<OutDetail> extracted(ArrayDeque<SoDetail> queue, List<Inventory> allotInvs, Set<SoDetail> soDetailSet) {
        Set<OutDetail> outSet = new HashSet<>(queue.size());
        Set<SoDetail> set = new HashSet<>(queue.size());
//        List<OutDetail>
        for (Inventory allotInv : allotInvs) {
            Double invQty = allotInv.getQuantity();

            while (!queue.isEmpty()) {
                OutDetail outDetail = new OutDetail();
                //取出队列的第一个元素
                SoDetail soDetail = queue.getFirst();
                //SO待填补的数量
                double soQty = soDetail.getOrderQuantity() - soDetail.getDeliveryQuantity();
                if (soQty == 0) {
                    queue.poll();
                    continue;
                }
                if (invQty < soQty) {
                    //库存不够分配，分配后直接跳出循环
                    soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + invQty);
                    soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_PART_SEND);
                    set.add(soDetail);
                    BeanUtils.copyProperties(soDetail, outDetail);
                    outDetail.setBoxCode(allotInv.getBoxCode());
                    outDetail.setCellCode(allotInv.getCellCode());
                    outDetail.setBatchName(allotInv.getBatchName());
                    outDetail.setErpAreaId(allotInv.getErpAreaId());
                    outSet.add(outDetail);
                    soDetailSet.add(soDetail);
                    break;
                } else {
                    //库存足够分配，全部填满SO的数量
                    soDetail.setDeliveryQuantity(soDetail.getOrderQuantity());
                    soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
                    BeanUtils.copyProperties(soDetail, outDetail);
                    outDetail.setBoxCode(allotInv.getBoxCode());
                    outDetail.setCellCode(allotInv.getCellCode());
                    outDetail.setBatchName(allotInv.getBatchName());
                    outDetail.setErpAreaId(allotInv.getErpAreaId());
                    outSet.add(outDetail);
                    set.add(soDetail);
                    soDetailSet.add(soDetail);

                    //扣减已分配的库存数量
                    invQty -= soQty;
                    //队列第一个元素被分配完毕，出队列
                    queue.poll();
                }
            }
        }
        soDetailService.updateBatchById(set);
        return outSet;


    }


    /**
     * 回传ERP
     *
     * @param
     * @param outBill
     */
//    public OrderToErpBO getErpBean(Set<OutDetail> outDetails, String outBill) {
//
//
//
//        Set<Integer> soDetailIds = outDetails.stream().map(OutDetail::getSoDetailId).collect(Collectors.toSet());
//        List<SoDetail> soDetails = soDetailService.listByIds(soDetailIds);
//        Map<Integer, List<SoDetail>> soDetailMap = soDetails.stream().collect(Collectors.groupingBy(SoDetail::getSoDetailId));
//        Set<String> billNo = soDetails.stream().map(SoDetail::getBillNo).collect(Collectors.toSet());
////        Set<String> billNo = soDetailMap.keySet();
//        List<SoMaster> soMasterList = soMasterService.list(new QueryWrapper<SoMaster>().in("bill_no", billNo));
//        Map<String, List<SoMaster>> soMasterSet = soMasterList.stream().collect(Collectors.groupingBy(SoMaster::getBillNo));
//        OrderToErpBO orderToErpBO = new OrderToErpBO();
//        //todo  生产任务单默认 88 24
//        orderToErpBO.setBillTypeId(24); //类型 88
//        orderToErpBO.setSourceBillTypeId(88); //
//        orderToErpBO.setRob(true); //红蓝字
//        orderToErpBO.setBillNo(outBill);//唯一单号
//        orderToErpBO.setBillDate(DateUtils.getNowDateString());//时间
//        List<OrderDetailBO> details = new ArrayList<>();
//        outDetails.forEach(item -> {
//            SoDetail sod = soDetailMap.get(item.getSoDetailId()).iterator().next();
//            OrderDetailBO orderDetailBO = new OrderDetailBO();
//            orderDetailBO.setSourceBillId(soMasterSet.get(sod.getBillNo()).iterator().next().getBeforeNum());//源单据id
//            orderDetailBO.setSourceBillDetailRowIndex(sod.getBomSplit());//行号
//            orderDetailBO.setAuxPropId(item.getPackDetailId());//辅助类型id
//            orderDetailBO.setBatchNo(sod.getDetailNo()); //批次
//            orderDetailBO.setQty(item.getDeliveryQuantity());//数量
//            orderDetailBO.setBatchNo(item.getBatchName()); //计划跟踪号
//            orderDetailBO.setStockId(item.getErpAreaId());
//            details.add(orderDetailBO);
//
//        });
//        orderToErpBO.setDetails(details);
//        return orderToErpBO;
//    }

    /**
     * 生成库存事务
     *
     * @param inventory   库存
     * @param currentUser 当前用户
     * @return 库存事务
     */
    public InventoryTransact toStockRequest(Inventory inventory, CurrentUser currentUser) {
        InventoryTransact inventoryTransact = new InventoryTransact();
        //Step1.准备数据
        //仓库
        inventoryTransact.setWareId(inventory.getWareId());
        inventoryTransact.setWareName(inventory.getWareName());
        //货主
        inventoryTransact.setToOrganizationId(inventory.getOrganizationId());
        inventoryTransact.setToOrganizationName(inventory.getOrganizationName());
        //库位
        inventoryTransact.setFromCellCode(inventory.getCellCode());
        //容器
        inventoryTransact.setFromBoxCode(inventory.getBoxCode());
        //物料
        inventoryTransact.setItemCode(inventory.getItemCode());
        inventoryTransact.setItemName(inventory.getItemName());
        inventoryTransact.setImgUrl(inventory.getImgUrl());
        //批次
        inventoryTransact.setFromBatchId(inventory.getBatchId());
        inventoryTransact.setFromBatchName(inventory.getBatchName());
        //数量
        inventoryTransact.setFromQuantity(inventory.getQuantity());
        //包装 转换率
        inventoryTransact.setFromPackDetailId(inventory.getPackDetailId());
        inventoryTransact.setFromPackDescribe(inventory.getPackDescribe());
        //创建人 时间
        inventoryTransact.setCreateUserId(currentUser.getUserId());
        inventoryTransact.setCreateUserName(currentUser.getUserName());
        inventoryTransact.setCreateTime(DateUtil.now());
        //事务类型
        inventoryTransact.setTransactType(InventoryConstant.INVENTORY_TYPE_OUT);
        //来源单据号
//        inventoryTransact.setBillNo(pickTask.getPickTaskCode());

        //Step2.保存，返回
        inventoryTransactService.save(inventoryTransact);
        return inventoryTransact;
    }


}
